#include "StdAfx.h"
#include "DBReader.h"

using namespace System;
using namespace System::IO;
using namespace System::Data::SqlClient;

DBReader::DBReader ()
{
	// Nothing here
}

void DBReader::Connect (SqlCommand ^Query)
{
	array<String^>^ ConnectionString = File::ReadAllLines(L"ConfigIP.txt");
	Query->Connection = gcnew SqlConnection(ConnectionString[0]);
	Query->Connection->Open();
	Query->CommandTimeout = 600;
}

void DBReader::Read (SqlCommand ^Query, int *N)
{
	SqlDataReader ^Reader;

	try
	{
		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			*N = Reader->GetInt32(0);
		}
		else
		{
			*N = 0;
		}
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		throw(Exception);
	}

	Reader->Close();
}

void DBReader::Read (SqlCommand ^Query, double *Vectors, int VectorsNum, int Dim)
{
	SqlDataReader ^Reader;
		
	try
	{
		Reader = Query->ExecuteReader();

		for (int m = 0; m < VectorsNum; ++m)
			for (int n = 0; n < Dim; ++n)
			{
				int i = m * Dim + n;
				
				if (Reader->Read())
				{
					Vectors[i] = Reader->GetDouble(0);
				}
				else
				{
					Vectors[i] = 0.0;
				}
			}
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		throw(Exception);
	}
	
	Reader->Close();
}

void DBReader::LoadFlightNums (int FlightID, int *VectorsNum, int *Dim, int Interval)
{
	Int32 ^SearchID = FlightID;
	Int32 ^Interv = Interval;
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadFlight @FlightID = " + SearchID->ToString() + ", @Mode = 'num', @Interval = " + Interv->ToString();
		Read(Query, VectorsNum);

		Query->CommandText = "EXECUTE GetDim @FlightID = " + SearchID->ToString();
		Read(Query, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadFlightNums (int FlightID, int Tact1, int Tact2, int *VectorsNum, int *Dim, int Interval)
{
	Int32 ^SearchID = FlightID;
	Int32 ^Tact_1 = Tact1;
	Int32 ^Tact_2 = Tact2;
	Int32 ^Interv = Interval;
	
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadFlightInterval @FlightID = " + SearchID->ToString() + ", @Tact1 = " + Tact_1->ToString() + ", @Tact2 = " + Tact_2->ToString() + ", @Mode = 'num', @Interval = " + Interv->ToString();
		Read(Query, VectorsNum);

		Query->CommandText = "EXECUTE GetDim @FlightID = " + SearchID->ToString();
		Read(Query, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadFlight (int FlightID, double *FlightVectors, int VectorsNum, int Dim, int Interval)
{
	Int32 ^SearchID = FlightID;
	Int32 ^Interv  = Interval;
	
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadFlight @FlightID = " + SearchID->ToString() + ", @Mode = 'vec', @Interval = " + Interv->ToString();
		Read(Query, FlightVectors, VectorsNum, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadFlight (int FlightID, double *FlightVectors, int Tact1, int Tact2, int VectorsNum, int Dim, int Interval)
{
	Int32 ^SearchID = FlightID;
	Int32 ^Tact_1 = Tact1;
	Int32 ^Tact_2 = Tact2;
	Int32 ^Interv = Interval;
	
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadFlightInterval @FlightID = " + SearchID->ToString() + ", @Tact1 = " + Tact_1->ToString() + ", @Tact2 = " + Tact_2->ToString() + ", @Mode = 'vec', @Interval = " + Interv->ToString();
		Read(Query, FlightVectors, VectorsNum, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadFlightSubsystem(int FlightID, int SubsystemID, double *FlightVectors, int Tact1, int Tact2, int VectorsNum, int Dim, int Interval)
{
	Int32 ^SearchID = FlightID;
	Int32 ^Tact_1 = Tact1;
	Int32 ^Tact_2 = Tact2;
	Int32 ^nSubsystemId = SubsystemID;
	Int32 ^Interv = Interval;
	
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadSubsystemsInterval @FlightID = " + SearchID->ToString() + ", @Tact1 = " + Tact_1->ToString() 
								+ ", @Tact2 = " + Tact_2->ToString() 
								+ ", @SubsystemId = " + nSubsystemId->ToString()
								+ ", @Mode = 'vec', @Interval = " + Interv->ToString();
		Read(Query, FlightVectors, VectorsNum, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadVectorsNums (int FlightID, int *Tacts, int N, int *VectorsNum, int *Dim)
{
	Int32 ^SearchID = FlightID;
	Int32 ^TactID = Tacts[0];
	String ^SelectedTacts = TactID->ToString();
	
	for (int n = 1; n < N; ++n)
	{
		TactID = Tacts[n];
		SelectedTacts += ", " + TactID->ToString();
	}

	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "SELECT COUNT(*) FROM RegVec WHERE (RegVec.ProcessedFlightId = " + SearchID->ToString() + " AND RegVec.Tact IN (" + SelectedTacts + "))";
		Read(Query, VectorsNum);

		Query->CommandText = "EXECUTE GetDim @FlightID = " + SearchID->ToString();
		Read(Query, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadVectors (int FlightID, double *Vectors, int *Tacts, int N, int VectorsNum, int Dim)
{
	Int32 ^SearchID = FlightID;
	Int32 ^TactID = Tacts[0];
	String ^SelectedTacts = TactID->ToString();

	for (int n = 1; n < N; ++n)
	{
		TactID = Tacts[n];
		SelectedTacts += ", " + TactID->ToString();
	}

	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "SELECT Val, ParamId, Tact FROM Value WHERE (Value.ProcessedFlightId = " + SearchID->ToString() + " AND Value.Tact IN (" + SelectedTacts + ")) ORDER BY Tact, ParamId";
		Read(Query, Vectors, VectorsNum, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadVectorsNums (int PlaneID, double Size, int *VectorsNum, int *Dim)
{
	Int32 ^SearchID = PlaneID;
	Int32 ^SampleSize = (int)Size;

	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadRandomVectors @PlaneID = " + SearchID->ToString() + ", @Size = " + SampleSize->ToString() + ", @Mode = 'num'";
		Read(Query, VectorsNum);

		Query->CommandText = "EXECUTE GetDim @FlightID = 2"; // We get flight vector dimension from second flight (eusistic)
		Read(Query, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadVectors (int PlaneID, double *Vectors, double Size, int VectorsNum, int Dim)
{	
	Int32 ^SearchID = PlaneID;
	Int32 ^SampleSize = (int)Size;
	
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadRandomVectors @PlaneID = " + SearchID->ToString() + ", @Size = " + SampleSize->ToString() + ", @Mode = 'vec'";
		Read(Query, Vectors, VectorsNum, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadSubsystemsVectorsNums(int PlaneID, int SubsystemID, double Size, int *VectorsNum, int *Dim)
{
	Int32 ^SearchID = PlaneID;
	Int32 ^SampleSize = (int)Size;
	Int32 ^SubsystemId = SubsystemID;

	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader = nullptr;
	try
	{
		Connect(Query);

		Query->CommandText = 
			"EXECUTE LoadRandomSubsystemsVectors @PlaneID = " + SearchID->ToString() + ", @Size = " + SampleSize->ToString() + ", @SubsystemId = " + SubsystemId->ToString() + ", @Mode = 'num'";
		//Read(Query, VectorsNum);

		//Query->CommandText = "EXECUTE GetSubsystemDim @PlaneID = " +  SearchID->ToString() + ", @SubsystemsId = " + SubsystemId->ToString();
		//Read(Query, Dim);
		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			*VectorsNum = Reader->GetInt32(0);
			*Dim = Reader->GetInt32(1);
		}
		else
		{
			*VectorsNum = 0;
			*Dim = 0;
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}


void DBReader::LoadSubsystemsVectors(int PlaneID, int SubsystemID, double *Vectors, double Size, int VectorsNum, int Dim)
{
	Int32 ^SearchID = PlaneID;
	Int32 ^SampleSize = (int)Size;
	Int32 ^nSubsystemId = (int)SubsystemID;
	
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadRandomSubsystemsVectors @PlaneID = " + SearchID->ToString() + ", @Size = " + SampleSize->ToString() 
																				+ ", @SubsystemId = " + nSubsystemId->ToString() + ", @Mode = 'vec'";
		Read(Query, Vectors, VectorsNum, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadFlightSubsystemsVectors(int FlightID, int SubsystemID, double *Vectors, double Size, int VectorsNum, int Dim)
{
	Int32 ^SearchID = FlightID;
	Int32 ^SampleSize = (int)Size;
	Int32 ^nSubsystemId = (int)SubsystemID;
	
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadRandomFlightSubsystemsVectors @FlightID = " + SearchID->ToString() + ", @Size = " + SampleSize->ToString() 
																				+ ", @SubsystemId = " + nSubsystemId->ToString() + ", @Mode = 'vec'";
		Read(Query, Vectors, VectorsNum, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadClusterVectorsNums (int PlaneID, double Size, int *VectorsNum, int *Dim, char *Date, int Label)
{
	String ^RunDate = gcnew String(Date);

	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadRandomClusterVectors @PlaneID, @Size, @Date, @Label, @Mode = 'num'";
		Query->Parameters->AddWithValue("@PlaneID", PlaneID);
		Query->Parameters->AddWithValue("@Size", (int)Size);
		Query->Parameters->AddWithValue("@Date", RunDate);
		Query->Parameters->AddWithValue("@Label", Label);
		Read(Query, VectorsNum);

		Query->Parameters->Clear();
		Query->CommandText = "EXECUTE GetDim @FlightID = 2"; // We get flight vector dimension from second flight (eusistic)
		Read(Query, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadClusterVectors (int PlaneID, double *Vectors, double Size, int VectorsNum, int Dim, char *Date, int Label)
{
	String ^RunDate = gcnew String(Date);

	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadRandomClusterVectors @PlaneID, @Size, @Date, @Label, @Mode = 'vec'";
		Query->Parameters->AddWithValue("@PlaneID", PlaneID);
		Query->Parameters->AddWithValue("@Size", (int)Size);
		Query->Parameters->AddWithValue("@Date", RunDate);
		Query->Parameters->AddWithValue("@Label", Label);
		Read(Query, Vectors, VectorsNum, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::GetFlightIDsNum (int PlaneID, int *Num)
{
	Int32 ^SearchID = PlaneID;
	
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);
	
		Query->CommandText = "SELECT COUNT(*) FROM ProcessedFlight JOIN Flight ON (ProcessedFlight.FlightID = Flight.Id) WHERE (Flight.PlaneId = " + SearchID->ToString() + ") AND ProcessedFlight.Id <> 8 AND ProcessedFlight.Id < 19";
		Read(Query, Num);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::GetFlightIDs (int PlaneID, double *IDs, int Num)
{
	Int32 ^SearchID = PlaneID;
	
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "SELECT ProcessedFlight.Id FROM ProcessedFlight JOIN Flight ON (ProcessedFlight.FlightID = Flight.Id) WHERE (Flight.PlaneId = " + SearchID->ToString() + ") AND ProcessedFlight.Id <> 8 AND ProcessedFlight.Id < 19";
		
		Reader = Query->ExecuteReader();

		for (int n = 0; n < Num; ++n)
		{
			if (Reader->Read())
			{
				IDs[n] = Reader->GetInt32(0);
			}
			else
			{
				IDs[n] = 0.0;
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::GetClusteredFlightIDsNum (char *Date, int *Num)
{
	String ^RunDate = gcnew String(Date);
	
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);
	
		Query->CommandText = "EXECUTE GetClusteredFlights @Date, 'num'";
		Query->Parameters->AddWithValue("@Date", RunDate);
		Read(Query, Num);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::GetClusteredFlightIDs (char *Date, double *IDs, int Num)
{
	String ^RunDate = gcnew String(Date);
	
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE GetClusteredFlights @Date, 'vec'";
		Query->Parameters->AddWithValue("@Date", RunDate);
		
		Reader = Query->ExecuteReader();

		for (int n = 0; n < Num; ++n)
		{
			if (Reader->Read())
			{
				IDs[n] = Reader->GetInt32(0);
			}
			else
			{
				IDs[n] = 0.0;
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadClusteringNums (int FlightID, int *VectorsNum, int *Size, char *Date)
{
	/*
	We want to load clustering results (nearest to the given Date):
	clusters' parameters, cluster centers i.e.,
	and cluster labels for the given flight FlightID.
	*/
	Int32 ^SearchID = FlightID;
	String ^RunDate = gcnew String(Date);

	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadClusteringNum @Date, @FlightID";
		Query->Parameters->AddWithValue("@Date", RunDate);
		Query->Parameters->AddWithValue("@FlightID", SearchID);
		Read(Query, VectorsNum);

		Query->CommandText = "EXECUTE LoadParameters @Date, @FlightID";
		
		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			*Size = int(Reader->GetBytes(0, 0, nullptr, 0, 0) / sizeof(double));
		}
		else
		{
			*Size = 0;
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}
	
	Query->Connection->Close();
}

void DBReader::LoadClustering (int FlightID, double *Labels, double *Params, int VectorsNum, int ParamSize, char *Date)
{
	/*
	We want to load clustering results (nearest to the given Date):
	clusters' parameters, cluster centers i.e.,
	and cluster labels for the given flight FlightID.
	*/
	Int32 ^SearchID = FlightID;
	String ^RunDate = gcnew String(Date);

	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadClusteringLbl @Date, @FlightID";
		Query->Parameters->AddWithValue("@Date", RunDate);
		Query->Parameters->AddWithValue("@FlightID", SearchID);

		Reader = Query->ExecuteReader();
		for (int i = 0; i < VectorsNum; ++i)
		{
			if (Reader->Read())
			{
				Labels[i] = Reader->GetInt32(0);
			}
			else
			{
				Labels[i] = 0.0;
			}
		}
		Reader->Close();

		Query->CommandText = "EXECUTE LoadParameters @Date, @FlightID";
		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			int Size = ParamSize * sizeof(double);
			array<Byte> ^ByteParams = gcnew array<Byte>(Size);
			Reader->GetBytes(0, 0, ByteParams, 0, Size);

			ConvertByteArrayToDoubleArray(ByteParams, Params, ParamSize);
		}
		else
		{
			Params[0] = 1.0;
			Params[1] = 2.0;
			Params[2] = 1.0;
			Params[3] = ParamSize - 4.0;
			for (int i = 4; i < ParamSize; ++i)
			{
				Params[i] = 0.0;
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadClusteringNums (int FlightID, int *VectorsNum, int *Size, int *UsedParamsNum, char *Date)
{
	/*
	We want to load clustering results (nearest to the given Date):
	clusters' parameters, cluster centers i.e.,
	and cluster labels for the given flight FlightID.
	*/
	Int32 ^SearchID = FlightID;
	String ^RunDate = gcnew String(Date);

	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadClusteringNum @Date, @FlightID";
		Query->Parameters->AddWithValue("@Date", RunDate);
		Query->Parameters->AddWithValue("@FlightID", SearchID);
		Read(Query, VectorsNum);

		Query->CommandText = "EXECUTE LoadParameters @Date, @FlightID";
		
		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			*Size = int(Reader->GetBytes(0, 0, nullptr, 0, 0) / sizeof(double));
			if(Reader->IsDBNull(1))
			{
				*UsedParamsNum = 0;
			}
			else
			{
				*UsedParamsNum = int(Reader->GetBytes(1, 0, nullptr, 0, 0) / sizeof(double));
			}
		}
		else
		{
			*Size = 0;
			*UsedParamsNum = 0;
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}
	
	Query->Connection->Close();
}

void DBReader::LoadClustering (int FlightID, double *Labels, double *Params, double *UsedParametersNames,
	int VectorsNum, int ParamSize, int UsedParamsNum, char *Date)
{
	/*
	We want to load clustering results (nearest to the given Date):
	clusters' parameters, cluster centers i.e.,
	and cluster labels for the given flight FlightID.
	*/
	Int32 ^SearchID = FlightID;
	String ^RunDate = gcnew String(Date);

	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadClusteringLbl @Date, @FlightID";
		Query->Parameters->AddWithValue("@Date", RunDate);
		Query->Parameters->AddWithValue("@FlightID", SearchID);

		Reader = Query->ExecuteReader();
		for (int i = 0; i < VectorsNum; ++i)
		{
			if (Reader->Read())
			{
				Labels[i] = Reader->GetInt32(0);
			}
			else
			{
				Labels[i] = 0.0;
			}
		}
		Reader->Close();

		Query->CommandText = "EXECUTE LoadParameters @Date, @FlightID";
		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			int Size = ParamSize * sizeof(double);
			int UsedParamsSize = UsedParamsNum * sizeof(double);
			array<Byte> ^ByteParams = gcnew array<Byte>(Size);
			array<Byte> ^ByteUsedParametersNames = gcnew array<Byte>(UsedParamsSize);
			Reader->GetBytes(0, 0, ByteParams, 0, Size);
			if(!Reader->IsDBNull(1))
			{
				Reader->GetBytes(1, 0, ByteUsedParametersNames, 0, UsedParamsSize);
			}
			ConvertByteArrayToDoubleArray(ByteParams, Params, ParamSize);
			ConvertByteArrayToDoubleArray(ByteUsedParametersNames, UsedParametersNames, UsedParamsNum);
		}
		else
		{
			Params[0] = 1.0;
			Params[1] = 2.0;
			Params[2] = 1.0;
			Params[3] = ParamSize - 4.0;
			for (int i = 4; i < ParamSize; ++i)
			{
				Params[i] = 0.0;
			}

			UsedParametersNames[0] = 1.0;
			UsedParametersNames[1] = 2.0;
			UsedParametersNames[2] = 1.0;
			UsedParametersNames[3] = UsedParamsNum - 4.0;
			for (int i = 4; i < UsedParamsNum; ++i)
			{
				UsedParametersNames[i] = 0.0;
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadMetricRealizationNum (char *MetricType, char *Date, int *RealizationsNum)
{
	String ^Type = gcnew String(MetricType);
	String ^RunDate = gcnew String(Date);

	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		if (RunDate->Length == 0)
		{
			Query->CommandText = "EXECUTE LoadMetricRealizations NULL, @Type, 'num'";
			Query->Parameters->AddWithValue("@Type", Type);
		}
		else
		{
			Query->CommandText = "EXECUTE LoadMetricRealizations @Date, @Type, 'num'";
			Query->Parameters->AddWithValue("@Type", Type);
			Query->Parameters->AddWithValue("@Date", RunDate);
		}
		Read(Query, RealizationsNum);
		Query->Parameters->Clear();
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadMetricRealizationNum (int ID, int *Size)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadMetricRealization @RealizationID";
		Query->Parameters->AddWithValue("@RealizationID", ID);

		Reader = Query->ExecuteReader();
		
		if (Reader->Read())
		{
			*Size = int(Reader->GetBytes(1, 0, nullptr, 0, 0) / sizeof(double));
		}
		else
		{
			*Size = 0;
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadMetricRealizationNum (int ID, int *Size, int *UsedSize)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadMetricRealization @RealizationID";
		Query->Parameters->AddWithValue("@RealizationID", ID);

		Reader = Query->ExecuteReader();
		
		if (Reader->Read())
		{
			*Size = int(Reader->GetBytes(1, 0, nullptr, 0, 0) / sizeof(double));
			if(Reader->IsDBNull(3))
			{
				*UsedSize = 0;
			}
			else
			{
				*UsedSize = int(Reader->GetBytes(3, 0, nullptr, 0, 0) / sizeof(double));
			}
		}
		else
		{
			*Size = 0;
			*UsedSize = 0;
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadMetricRealization (char *MetricType, char *Date, double *IDs, char *Comments[], int RealizationsNum)
{
	String ^Type = gcnew String(MetricType);
	String ^RunDate = gcnew String(Date);

	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		if (RunDate->Length == 0)
		{
			Query->CommandText = "EXECUTE LoadMetricRealizations NULL, @Type, 'ids'";
			Query->Parameters->AddWithValue("@Type", Type);
		}
		else
		{
			Query->CommandText = "EXECUTE LoadMetricRealizations @Date, @Type, 'ids'";
			Query->Parameters->AddWithValue("@Type", Type);
			Query->Parameters->AddWithValue("@Date", RunDate);
		}

		Reader = Query->ExecuteReader();
		
		for (int n = 0; n < RealizationsNum; ++n)
		{
			String ^Comment;
			
			if (Reader->Read())
			{
				IDs[n] = Reader->GetInt32(0);
				Comment = Reader->GetString(1);
				for (int i = 0; i < Comment->Length; ++i)
				{
					Comments[n][i] = char(Comment[i]);
				}
				Comments[n][Comment->Length] = '\0';
			}
			else
			{
				IDs[n] = 0.0;
				Comments[n][0] = '\0';
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadMetricRealization (int ID, char *Type, double *Params, char *Comment, int Size)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadMetricRealization @RealizationID";
		Query->Parameters->AddWithValue("@RealizationID", ID);

		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			String ^MetricType = Reader->GetString(0);
			String ^MetricComment = Reader->GetString(2);
			int ParamSize = Size * sizeof(double);
			array<Byte> ^ByteParams = gcnew array<Byte>(ParamSize);

			for (int i = 0; i < MetricType->Length; ++i)
			{
				Type[i] = char(MetricType[i]);
			}
			Type[MetricType->Length] = '\0';

			for (int i = 0; i < MetricComment->Length; ++i)
			{
				Comment[i] = char(MetricComment[i]);
			}
			Comment[MetricComment->Length] = '\0';

			Reader->GetBytes(1, 0, ByteParams, 0, ParamSize);

			ConvertByteArrayToDoubleArray(ByteParams, Params, Size);
		}
		else
		{
			Type[0] = '\0';
			Comment[0] = '\0';

			/*Params[0] = 1.0;
			Params[1] = 2.0;
			Params[2] = 1.0;
			Params[3] = Size - 4.0;
			for (int i = 4; i < Size; ++i)
			{
				Params[i] = 0.0;
			}*/
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadMetricRealization (int ID, char *Type, double *Params, char *Comment, int Size,
	double *UsedParametersNames, int UsedSize)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadMetricRealization @RealizationID";
		Query->Parameters->AddWithValue("@RealizationID", ID);

		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			String ^MetricType = Reader->GetString(0);
			String ^MetricComment = Reader->GetString(2);
			int ParamSize = Size * sizeof(double);
			int UsedParamSize = UsedSize * sizeof(double);
			array<Byte> ^ByteParams = gcnew array<Byte>(ParamSize);
			array<Byte> ^ByteUsedParamsNames = gcnew array<Byte>(UsedParamSize);

			for (int i = 0; i < MetricType->Length; ++i)
			{
				Type[i] = char(MetricType[i]);
			}
			Type[MetricType->Length] = '\0';

			for (int i = 0; i < MetricComment->Length; ++i)
			{
				Comment[i] = char(MetricComment[i]);
			}
			Comment[MetricComment->Length] = '\0';

			Reader->GetBytes(1, 0, ByteParams, 0, ParamSize);
			if(!Reader->IsDBNull(3))
			{
				Reader->GetBytes(3, 0, ByteUsedParamsNames, 0, UsedParamSize);
			}

			ConvertByteArrayToDoubleArray(ByteParams, Params, Size);
			ConvertByteArrayToDoubleArray(ByteUsedParamsNames, UsedParametersNames, UsedSize);
		}
		else
		{
			Type[0] = '\0';
			Comment[0] = '\0';

			/*Params[0] = 1.0;
			Params[1] = 2.0;
			Params[2] = 1.0;
			Params[3] = Size - 4.0;
			for (int i = 4; i < Size; ++i)
			{
				Params[i] = 0.0;
			}*/
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::GetEvaluatedFlightIDsNum (int ID, int *Num)
{
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadMetric @RealizationID, @Mode = 'flightsnum'";
		Query->Parameters->AddWithValue("@RealizationID", ID);
		Read(Query, Num);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::GetEvaluatedFlightIDs (int ID, double *IDs, int Num)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadMetric @RealizationID, @Mode = 'flights'";
		Query->Parameters->AddWithValue("@RealizationID", ID);
	
		Reader = Query->ExecuteReader();

		for (int n = 0; n < Num; ++n)
		{
			if (Reader->Read())
			{
				IDs[n] = Reader->GetInt32(0);
			}
			else
			{
				IDs[n] = 0.0;
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadMetricTypesNum (int ID, int FlightID, int *MetricsNum)
{
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadMetricTypes @MetricRealizationID, @FlightID, 'num'";
		Query->Parameters->AddWithValue("@MetricRealizationID", ID);
		Query->Parameters->AddWithValue("@FlightID", FlightID);

		Read(Query, MetricsNum);
		Query->Parameters->Clear();
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadMetricTypes (int ID, int FlightID, double *TypeIDs, char *Types[], int MetricsNum)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadMetricTypes @MetricRealizationID, @FlightID, 'types'";
		Query->Parameters->AddWithValue("@MetricRealizationID", ID);
		Query->Parameters->AddWithValue("@FlightID", FlightID);

		Reader = Query->ExecuteReader();
		
		for (int n = 0; n < MetricsNum; ++n)
		{
			String ^Comment;
			
			if (Reader->Read())
			{
				TypeIDs[n] = Reader->GetInt32(0);
				Comment = Reader->GetString(1);
				for (int i = 0; i < Comment->Length; ++i)
				{
					Types[n][i] = char(Comment[i]);
				}
				Types[n][Comment->Length] = '\0';
			}
			else
			{
				TypeIDs[n] = 0.0;
				Types[n][0] = '\0';
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadMetricNum (int ID, int FlightID, int TypeID, int *Size)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadMetric @RealizationID, @FlightID, @TypeID, @Mode = 'num'";
		Query->Parameters->AddWithValue("@RealizationID", ID);
		Query->Parameters->AddWithValue("@FlightID", FlightID);
		Query->Parameters->AddWithValue("@TypeID", TypeID);
		
		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			*Size = int(Reader->GetInt32(0) / sizeof(double));
		}
		else
		{
			*Size = 0;
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadMetric (int ID, int FlightID, int TypeID, double *Values, int Size)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadMetric @RealizationID, @FlightID, @TypeID, @Mode = 'metric'";
		Query->Parameters->AddWithValue("@RealizationID", ID);
		Query->Parameters->AddWithValue("@FlightID", FlightID);
		Query->Parameters->AddWithValue("@TypeID", TypeID);
		
		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			int ValueSize = Size * sizeof(double);
			array<Byte> ^ByteValues = gcnew array<Byte>(ValueSize);
			
			Reader->GetBytes(0, 0, ByteValues, 0, ValueSize);

			ConvertByteArrayToDoubleArray(ByteValues, Values, Size);
		}
		else
		{
			Values[0] = 1.0;
			Values[1] = 2.0;
			Values[2] = 1.0;
			Values[3] = Size - 4.0;
			for (int i = 4; i < Size; ++i)
			{
				Values[i] = 0.0;
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadProblems (int FlightID, double *Problems, int Size)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadProblems @FlightID";
		Query->Parameters->AddWithValue("@FlightID", FlightID);
		Reader = Query->ExecuteReader();
		
		for (int i = 0; i < Size; ++i)
		{
			if (Reader->Read())
			{
				Problems[i] = bool(Reader->GetValue(0));
			}
			else
			{
				Problems[i] = 1;
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadFlightVectorsNums (int FlightID, double Size, int *VectorsNum, int *Dim)
{
	Int32 ^SearchID = FlightID;
	Int32 ^SampleSize = (int)Size;

	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadRandomFlightVectors @FlightID = " + SearchID->ToString() + ", @Size = " + SampleSize->ToString() + ", @Mode = 'num'";
		Read(Query, VectorsNum);

		Query->CommandText = "EXECUTE GetDim @FlightID = " + SearchID->ToString();
		Read(Query, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadFlightVectors (int FlightID, double *Vectors, double Size, int VectorsNum, int Dim)
{	
	Int32 ^SearchID = FlightID;
	Int32 ^SampleSize = (int)Size;
	
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE LoadRandomFlightVectors @FlightID = " + SearchID->ToString() + ", @Size = " + SampleSize->ToString() + ", @Mode = 'vec'";
		Read(Query, Vectors, VectorsNum, Dim);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

int DBReader::GetClustersNum (char *Date)
{
	int ClustersNum = -1;
	String ^RunDate = gcnew String(Date);

	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE GetClustersNum @Date";
		Query->Parameters->AddWithValue("@Date", RunDate);
		Read(Query, &ClustersNum);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();

	return ClustersNum;
}

void DBReader::GetClusteringRunDate (int MetricRealizationID, char *Date)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE GetClusteringRunDate @RealizationID";
		Query->Parameters->AddWithValue("@RealizationID", MetricRealizationID);

		Reader = Query->ExecuteReader();

		if (Reader->Read())
		{
			System::DateTime ^DateTime = Reader->GetDateTime(0);
			String ^DateString = DateTime->ToString("yyyy-MM-dd HH:mm:ss");
			int N = DateString->Length;

			for (int n = 0; n < N; ++n)
			{
				Date[n] = DateString[n];
			}
			Date[N] = '\0';
		}
		else
		{
			strcpy(Date, "\0");
		}
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::ConvertByteArrayToDoubleArray(array<Byte> ^bytedata, double *data, int size)
{
	for(int i = 0; i < size; ++i)
	{
		data[i] = BitConverter::ToDouble(bytedata, i * sizeof(double));
	}
}

void DBReader::GetParameterIDsNum (int PlaneID, int *Num)
{
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);
	
		Query->CommandText = "EXECUTE GetParametersNames @PlaneID, 'num'";
		Query->Parameters->AddWithValue("@PlaneID", PlaneID);
		Read(Query, Num);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::GetParameterIDs (int PlaneID, double *IDs, int Num)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE GetParametersNames @PlaneID, 'vec'";
		Query->Parameters->AddWithValue("@PlaneID", PlaneID);
		
		Reader = Query->ExecuteReader();

		for (int n = 0; n < Num; ++n)
		{
			if (Reader->Read())
			{
				IDs[n] = Reader->GetInt32(0);
			}
			else
			{
				IDs[n] = 0.0;
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadParameterNum (int FlightID, int ParameterID, int *Num)
{
	SqlCommand ^Query = gcnew SqlCommand();

	try
	{
		Connect(Query);
	
		Query->CommandText = "EXECUTE GetParameterValues @FlightID, @ParameterID, 'num'";
		Query->Parameters->AddWithValue("@FlightID", FlightID);
		Query->Parameters->AddWithValue("@ParameterID", ParameterID);
		Read(Query, Num);
	}
	catch(System::Exception ^Exception)
	{
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}

void DBReader::LoadParameter (int FlightID, double *Values, int ParameterID, int Num)
{
	SqlCommand ^Query = gcnew SqlCommand();
	SqlDataReader ^Reader;

	try
	{
		Connect(Query);

		Query->CommandText = "EXECUTE GetParameterValues @FlightID, @ParameterID, 'vec'";
		Query->Parameters->AddWithValue("@FlightID", FlightID);
		Query->Parameters->AddWithValue("@ParameterID", ParameterID);
		
		Reader = Query->ExecuteReader();

		for (int n = 0; n < Num; ++n)
		{
			if (Reader->Read())
			{
				Values[n] = Reader->GetDouble(0);
			}
			else
			{
				Values[n] = 0.0;
			}
		}
		Reader->Close();
	}
	catch(System::Exception ^Exception)
	{
		if (Reader != nullptr)
		{
			Reader->Close();
		}
		if (Query->Connection != nullptr)
		{
			Query->Connection->Close();
		}
		throw(Exception);
	}

	Query->Connection->Close();
}